package com.xxm.util

import android.media.AudioFormat
import android.media.AudioManager
import android.media.AudioRecord
import android.media.AudioTrack
import android.media.MediaCodec
import android.media.MediaExtractor
import android.media.MediaFormat
import android.util.Log
import kotlinx.coroutines.*
import java.io.File
import kotlin.math.min

class AudioPlayer {
    private val TAG = "AudioPlayer"
    private var minBufferSize = 0
    private var sampleRate = 44100
    private var channel = AudioFormat.CHANNEL_OUT_DEFAULT
    private var audioFormat = AudioFormat.ENCODING_PCM_16BIT
    private var streamType = AudioManager.STREAM_MUSIC
    private var model = AudioTrack.MODE_STREAM
    private var audioMine = "audio/"

    private var audioTrack: AudioTrack? = null
    private var extractor: MediaExtractor? = null
    private var mediaFormat: MediaFormat? = null
    private var codec: MediaCodec? = null


    fun createPlayer() {
        minBufferSize = AudioTrack.getMinBufferSize(
            sampleRate, //采样 48000
            channel, //声道 4
            audioFormat //编码 2
        )
        Log.d(TAG, "输出最小缓存大小:${minBufferSize}")
        audioTrack = AudioTrack(streamType, sampleRate, channel, audioFormat, minBufferSize, model)
        Log.d(TAG, "init ${audioTrack}")
    }


    fun playMp4(path: String) {
        if (!File(path).exists()) {
            Log.e(TAG, "视频不存在")
            return
        }
        GlobalScope.launch(Dispatchers.IO) {
           try {
               extractor = MediaExtractor()
               extractor?.setDataSource(path)
               initVideoInfo()
               createPlayer()
               codec = MediaCodec.createDecoderByType(audioMine)
               codec?.configure(mediaFormat, null, null, 0)

               codec?.start()
               audioTrack?.play()


               val bufferInfo = MediaCodec.BufferInfo()
               while (isActive) {
                   val index = codec!!.dequeueInputBuffer(1000)
                   if (index > 0) {
                       val inputBuffer = codec!!.getInputBuffer(index)
                       val sampleSize = extractor?.readSampleData(inputBuffer!!, 0)
                       sampleSize?.run {
                           if (this < 0) {
                               codec?.queueInputBuffer(index, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM)
                           } else {

                               codec?.queueInputBuffer(index, 0, sampleSize, extractor!!.sampleTime, 0)
                               extractor?.advance()
                           }
                       }

                   }

                   var outputIndex = codec!!.dequeueOutputBuffer(bufferInfo, 10000)
                   if (outputIndex >= 0) {
                       val outputBuffer = codec!!.getOutputBuffer(outputIndex)
                       val data = ByteArray(bufferInfo.size)
                       outputBuffer?.get(data)
                       audioTrack?.write(data, 0, bufferInfo.size)
                       codec?.releaseOutputBuffer(outputIndex, false)
                   }
               }
           }catch (e :java.lang.Exception){
               e.printStackTrace()
           }finally {
               withContext(Dispatchers.Main){
                  // release()
               }
           }
        }
    }

     fun release() {
         Log.d(TAG, "release ${audioTrack}")
        audioTrack?.stop()
        audioTrack?.release()
        codec?.release()

        minBufferSize = 0
        sampleRate = 44100
        channel = AudioFormat.CHANNEL_OUT_DEFAULT
        audioFormat = AudioFormat.ENCODING_PCM_16BIT
        streamType = AudioManager.STREAM_MUSIC
        model = AudioTrack.MODE_STREAM
        audioMine = "audio/"

        audioTrack = null
        extractor = null
        mediaFormat = null
        codec = null
    }


    private fun initVideoInfo() {
        extractor?.run {
            for (i in 0 until trackCount) {
                 mediaFormat = getTrackFormat(i)
                val mineType = mediaFormat?.getString(MediaFormat.KEY_MIME)
                if (mineType?.startsWith(audioMine) == true) {
                    selectTrack(i)
                    audioMine = mineType
                    sampleRate = mediaFormat!!.getInteger(MediaFormat.KEY_SAMPLE_RATE)
                    val outChannel = mediaFormat!!.getInteger(MediaFormat.KEY_CHANNEL_COUNT)
                    channel = if (outChannel == 1) AudioFormat.CHANNEL_OUT_MONO else AudioFormat.CHANNEL_OUT_STEREO
                    return
                }
            }
        }
    }
}